package com.example.job.handler;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.example.core.constants.CacheConstants;
import com.example.core.constants.Constants;
import com.example.core.constants.MessageConstants;
import com.example.core.enums.MessageType;
import com.example.job.domain.exam.Exam;
import com.example.job.domain.exam.UserExamScore;
import com.example.job.domain.message.Message;
import com.example.job.domain.message.MessageText;
import com.example.job.domain.message.vo.MessageCacheVO;
import com.example.job.domain.message.vo.MessageTextCacheVO;
import com.example.job.mapper.exam.ExamMapper;
import com.example.job.mapper.exam.UserExamMapper;
import com.example.job.mapper.exam.UserSubmitMapper;
import com.example.job.service.IMessageService;
import com.example.job.service.IMessageTextService;
import com.example.job.service.impl.MessageServiceImpl;
import com.example.job.service.impl.MessageTextServiceImpl;
import com.example.redis.service.RedisService;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Component
public class ExamNoticeHandler {

    @Autowired
    private UserExamMapper userExamMapper;

    @Autowired
    private ExamMapper examMapper;

    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Autowired
    private MessageServiceImpl messageService;

    @Autowired
    private MessageTextServiceImpl messageTextService;

    @Autowired
    private RedisService redisService;

    @Value("${job.exam.statistic.period:1}")
    private Integer minusDay;

    //定时任务发送比赛结果
    //每天00:00执行  查询前一天竞赛的排名情况推送给用户
    @XxlJob("examResultNoticeHandler")
    @Transactional(rollbackFor = Exception.class)
    public void examResultNoticeHandler() {
        List<MessageText> messageTextList = statisticExamResultAndCreateMsg();
        if (messageTextList == null) {
            return;
        }
        sendExamResult(messageTextList);
    }

    private List<MessageText> statisticExamResultAndCreateMsg() {
        //先查询前一天的所有竞赛
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime minusDayTime = now.minusDays(minusDay);
        List<Exam> examList = examMapper.selectList(new LambdaQueryWrapper<Exam>()
                .ge(Exam::getEndTime, minusDayTime)
                .le(Exam::getEndTime, LocalDateTime.now()));
        if (CollectionUtils.isEmpty(examList)) {
            return null;
        }
        Set<Long> examIdSet = examList.stream().map(Exam::getExamId).collect(Collectors.toSet());
        List<UserExamScore> userExamScoreList = userSubmitMapper.selectUserExamScoreList(examIdSet);
        if (CollectionUtils.isEmpty(userExamScoreList)) {
            return null;
        }
        Map<Long, List<UserExamScore>> userExamScoreMap =
                userExamScoreList.stream().collect(Collectors.groupingBy(UserExamScore::getExamId));
        return statisticExamResultAndCreateMsg(examList, userExamScoreMap, userExamScoreList);
    }

    private List<MessageText> statisticExamResultAndCreateMsg(List<Exam> examList,
                                                              Map<Long, List<UserExamScore>> userExamScoreMap,
                                                              List<UserExamScore> userExamScoreList) {
        List<MessageText> messageTextList = new ArrayList<>();
        for (Exam exam : examList) {
            Long examId = exam.getExamId();
            List<UserExamScore> userExamScores = userExamScoreMap.get(examId);
            if (CollectionUtils.isEmpty(userExamScores)) {
                continue;
            }
            int examRank = 1; //排名从第一名开始
            int totalUser = userExamScores.size();  //参赛总人数
            for (UserExamScore userExamScore : userExamScores) {
                userExamScore.setExamRank(examRank);
                String content = "您参与的竞赛：" + exam.getTitle() + ":\n  本次参赛共"
                        + totalUser + "人，您排名：第" + examRank + "名！";
                MessageText messageText = new MessageText(MessageConstants.EXAM_RESULT_MSG_TITLE, content,
                        userExamScore.getUserId(), MessageType.SYSTEM_MESSAGE.getValue());
                messageTextList.add(messageText);
                examRank++;
            }
        }
        userExamMapper.updateUserScoreAndRank(userExamScoreList);  //更新用户总分、排名信息到
        return messageTextList;
    }

    private void sendExamResult(List<MessageText> messageTextList) {
        //批量插入messageTextList
        messageTextService.batchInsert(messageTextList);
        Map<String, MessageTextCacheVO> messageTextCacheVOMap = new HashMap<>();
        List<Message> messageList = new ArrayList<>();
        for (MessageText messageText : messageTextList) {
            MessageTextCacheVO messageTextCacheVO = new MessageTextCacheVO();
            BeanUtils.copyProperties(messageText, messageTextCacheVO);
            messageTextCacheVOMap.put(String.valueOf(messageText.getTextId()), messageTextCacheVO);

            Message message = new Message(messageText.getTextId(), Constants.DEFAULT_SYSTEM_USER_ID,
                    messageText.getUserId(), Constants.FALSE);
            messageList.add(message);
        }
        //批量插入messageList
        messageService.batchInsert(messageList);
        for (Message message : messageList) {
            MessageCacheVO messageCacheVO = new MessageCacheVO();
            BeanUtils.copyProperties(message, messageCacheVO);
            messageCacheVO.setReceiveTime(message.getCreateTime());
            String userMsgListKey = getUserMsgListKey(message.getRecId());
            redisService.leftPushForList(userMsgListKey, messageCacheVO);
        }

        String msgDetailKey = getMsgDetailKey();
        redisService.setCacheMap(msgDetailKey, messageTextCacheVOMap);
    }

    private String getUserMsgListKey(Long userId) {
        return CacheConstants.USER_MESSAGE_LIST + userId;
    }

    private String getMsgDetailKey() {
        return CacheConstants.MESSAGE_DETAIL;
    }
}
